#include "org_c_jni_JniUtil.h"
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#define LOG_TAG "JNIUTIL"
#ifdef __ANDROID__
#include <android/log.h>
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#else
#define LOGI(message, ...) NULL
#define LOGW(message, ...) NULL
#define LOGE(message, ...) NULL
#define LOGF(message, ...) NULL
#endif //ANDROID
#ifdef __cplusplus
extern "C" {
#endif //__cplusplus
typedef struct JAVAINFO {
	JNIEnv *env;
	JavaVM *jvm;
} JAVAINFO;
JAVAINFO *javaInfo = NULL;

//typedef void (*StringCallBack)(int action,char* data,int dataLen);

int doBeforeUseJNI() {
	if (javaInfo->jvm == NULL) {
		LOGW("'JavaVM' is null,is init()?");
		return JNI_ERR;
	}
	if (javaInfo->env == NULL) {
		LOGW("'JavaEnv' is null");
		return JNI_ERR;
	}
	int check = javaInfo->jvm->GetEnv((void **) &(javaInfo->env),
			JNI_VERSION_1_6);
	if (check == JNI_EDETACHED) {
		javaInfo->jvm->AttachCurrentThread(&(javaInfo->env), NULL);
	}
	return check;
}
;
void doAfterUseJNI(int resultAtPre) {
	if (javaInfo->jvm == NULL) {
		LOGW("'JavaVM' is null,is init()?");
		return;
	}
	if (javaInfo->env == NULL) {
		LOGW("'JavaEnv' is null");
		return;
	}
	if (resultAtPre == JNI_EDETACHED) {
		LOGI("DetachCurrentThread");
		int detach = javaInfo->jvm->DetachCurrentThread();
	}
	return;
}

void Java_org_c_jni_JniUtil_initJniEnvironment(JNIEnv *env, jclass zlass) {
	if (javaInfo == NULL) {
		struct JAVAINFO* data = (JAVAINFO*) (malloc(sizeof(JAVAINFO)));
		env->GetJavaVM(&(data->jvm));
		data->jvm->GetEnv(reinterpret_cast<void**>(&(data->env)),
				JNI_VERSION_1_6);
		javaInfo = data;
	}
}
void JniCallStaticVoidMethod(const char* className, const char* methodName,
		const char* methodSign, ...) {
	if (javaInfo == NULL || javaInfo->env == NULL) {
		LOGE("javaInfo == NULL || javaInfo->env == NULL,not init?");
		return;
	}
	int check = doBeforeUseJNI();
	jclass clsstring = javaInfo->env->FindClass(className);
	if (clsstring == NULL) {
		LOGE("%s is not be find", className);
		doAfterUseJNI(check);
		return;
	}
	jmethodID method = javaInfo->env->GetStaticMethodID(clsstring, methodName,
			methodSign);
	if (method == NULL) {
		LOGE("%s %s is not be find", methodName, methodSign);
		doAfterUseJNI(check);
		return;
	}
	va_list args;
	va_start(args, methodSign);
	javaInfo->env->functions->CallStaticVoidMethodV(javaInfo->env, clsstring,
			method, args);
	va_end(args);
	doAfterUseJNI(check);
}
JNIEXPORT void JNICALL Java_org_c_jni_JniUtil_callbackJniString(JNIEnv *env,
		jclass, jlong pcb, jint action, jstring data, jint dataLen) {
	const char * temp = env->GetStringUTFChars(data, 0);
	if (pcb != 0) {
		StringCallBack sb = (StringCallBack)pcb;
		sb(action, (char*)temp, dataLen);
	} else {
		LOGE("StringCallback is null");
	}
	env->ReleaseStringUTFChars(data, temp);

}
void testStringCallBack(int action,const char* data, int dataLen) {
	LOGI("testStringCallBack  action %d,data %s, dataLen %d", action, data,
			dataLen);
}

JNIEXPORT void JNICALL Java_org_c_jni_JniUtil_test(JNIEnv *, jclass) {
	LOGI("testStringCallBack point: %lld",testStringCallBack);
	JniCallStaticVoidMethod("org/c/jni/MainActivity", "NativeCall", "(JI)V",
			(jlong)testStringCallBack,119);
}

#ifdef __cplusplus
}
#endif //__cplusplus
